package com.atguigu.tingshu.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.AccountDeductService;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private AlbumFeignClient albumFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private OrderDerateMapper orderDerateMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private AccountDeductService accountDeductService;

    @Autowired
    private RabbitService rabbitService;

    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //2.初始化价格（原价、订单价、减免价）跟商品相关（明细列表、优惠列表）变量
        BigDecimal originalAmount = new BigDecimal("0.00");
        BigDecimal orderAmount = new BigDecimal("0.00");
        BigDecimal derateAmount = new BigDecimal("0.00");
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        //1.购买vip  "付款项目类型: 1001-专辑 1002-声音 1003-vip会员"
        if (SystemConstant.ORDER_ITEM_TYPE_VIP.equals(tradeVo.getItemType())) {
            Long itemId = tradeVo.getItemId();
            //1.1 进行远程调用用户模块进行获取vip信息
            VipServiceConfig vipServiceConfig = userFeignClient.getVipServiceConfig(itemId).getData();
            originalAmount = vipServiceConfig.getPrice();
            orderAmount = vipServiceConfig.getDiscountPrice();
            //1.2 判断原价和订单价格是否相等
            derateAmount = originalAmount.subtract(orderAmount);
            //1.3 封装订单优惠
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
            orderDerateVo.setDerateAmount(derateAmount);
            orderDerateVo.setRemarks("限时优惠" + derateAmount);
            orderDerateVoList.add(orderDerateVo);

            //1.4 封装订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(itemId);
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVo.setItemPrice(originalAmount);
            orderDetailVoList.add(orderDetailVo);

        } else if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(tradeVo.getItemType())) {
            //2.购买专辑
            Long albumId = tradeVo.getItemId();
            //2.1 获取专辑的id
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData();
            BigDecimal discount = albumInfo.getDiscount();
            BigDecimal vipDiscount = albumInfo.getVipDiscount();

            Boolean aBoolean = userFeignClient.isPaidAlbum(albumId).getData();
            if (aBoolean) {
                throw new GuiguException(500, "请勿重复购买专辑");
            }
            //2.2 进行判断是否为vip 专辑是否进行打折
            Boolean isVIP = false;
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
                isVIP = true;
            }
            originalAmount = albumInfo.getPrice();
            orderAmount = originalAmount;

            //4.4.1 是否普通用户存在普通用户折扣
            if (!isVIP && discount.doubleValue() != -1) {
                orderAmount =
                        originalAmount.multiply(discount).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
            }
            //4.4.2 是否会员存在会员折扣
            if (isVIP && vipDiscount.doubleValue() != -1) {
                orderAmount =
                        originalAmount.multiply(vipDiscount).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
            }

            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(albumId);
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVo.setItemPrice(originalAmount);
            orderDetailVoList.add(orderDetailVo);


            //2.4 存在减免
            if (originalAmount.compareTo(orderAmount) > 0) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                derateAmount = originalAmount.subtract(orderAmount);
                orderDerateVo.setDerateAmount(originalAmount.subtract(orderAmount));
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVo.setRemarks("限时优惠" + orderDerateVo.getDerateAmount());
                orderDerateVoList.add(orderDerateVo);
            }


        } else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(tradeVo.getItemType())) {
            //3.获取声音详情
            //3.1 获取声音的未购买的列表 以实现
            Long trackId = tradeVo.getItemId();
            List<TrackInfo> trackInfoList = albumFeignClient.findPaidTrackInfoList(trackId, tradeVo.getTrackCount()).getData();
            Assert.notNull(trackInfoList, "用户没有购买声音！");
            //3.2 获取专辑的id 价格以及各种参数
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId()).getData();
            Assert.notNull(albumInfo, "专辑不存在！");
            BigDecimal price = albumInfo.getPrice();
            originalAmount = price.multiply(BigDecimal.valueOf(trackInfoList.size()));
            orderAmount = originalAmount;

            orderDetailVoList = trackInfoList.stream().map(trackInfo -> {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(trackInfo.getId());
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                orderDetailVo.setItemPrice(price);
                return orderDetailVo;

            }).collect(Collectors.toList());

        }
        //封装订单信息
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);

        //4.封装其他的订单信息
        orderInfoVo.setItemType(tradeVo.getItemType());
        //4.1 获取流水号 时间戳 避免用户的重复提交
        orderInfoVo.setTimestamp(System.currentTimeMillis());
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setItemType(tradeVo.getItemType());


        String key = RedisConstant.ORDER_TRADE_NO_PREFIX + userId;
        String value = IdUtil.randomUUID();
        //4.2 发送redis消息设置过期时间 设置过期时间,防止订单被重复提交
        redisTemplate.opsForValue().set(key, value, RedisConstant.ORDER_TRADE_EXPIRE, TimeUnit.MINUTES);
        orderInfoVo.setTradeNo(value);
        //4.3 获取签名 用于判断订单是否被更改
        Map<String, Object> map = BeanUtil.beanToMap(orderInfoVo, false, true);
        String sign = SignHelper.getSign(map);
        orderInfoVo.setSign(sign);
        return orderInfoVo;
    }

    /**
     * 提交订单
     *
     * @param orderInfoVo
     * @param userId
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Map<String, String> submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //1. 进行订单的流水号确认
        String key = RedisConstant.ORDER_TRADE_NO_PREFIX + userId;
        //1.1 如何保证流水号的原子性
        String tradeNo = orderInfoVo.getTradeNo();
        String scriptText = """
                if redis.call("get",KEYS[1]) == ARGV[1]
                then
                    return redis.call("del",KEYS[1])
                else
                    return 0
                end
                """;
        DefaultRedisScript defaultRedisScript = new DefaultRedisScript();
        defaultRedisScript.setScriptText(scriptText);
        defaultRedisScript.setResultType(Boolean.class);
        Boolean execute = (Boolean) redisTemplate.execute(defaultRedisScript, Arrays.asList(key), tradeNo);
        if (!execute) {
            throw new GuiguException(500, "订单已过期！");
        }

        //2. 订单的签名确认
        Map<String, Object> map = BeanUtil.beanToMap(orderInfoVo);
        map.remove("payWay");
        //2.2 进行验签
        SignHelper.checkSign(map);
        //2.3 保存订单信息

        OrderInfo orderInfo = this.saveOrderInfo(orderInfoVo, userId);
        String payWay = orderInfoVo.getPayWay();
        if (SystemConstant.ORDER_PAY_ACCOUNT.equals(payWay)) {
            accountDeductService.handleAccountDeduct(orderInfo);
        }
        //3.微信支付
        if (SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(payWay)) {
            rabbitService.sendDealyMessage(
                    MqConst.EXCHANGE_CANCEL_ORDER,
                    MqConst.ROUTING_CANCEL_ORDER,
                    orderInfo.getId(),
                    MqConst.CANCEL_ORDER_DELAY_TIME);

        }
        //4.支付宝支付
        if (SystemConstant.ORDER_PAY_WAY_ALIPAY.equals(payWay)) {

        }
        return Map.of("orderNo", orderInfo.getOrderNo());
    }

    @Override
    public OrderInfo saveOrderInfo(OrderInfoVo orderInfoVo, Long userId) {
        //1.设置订单状态为未支付
        OrderInfo orderInfo = BeanUtil.copyProperties(orderInfoVo, OrderInfo.class);
        orderInfo.setPayWay(SystemConstant.ORDER_PAY_ACCOUNT);
        orderInfo.setUserId(userId);
        //2.订单号使用当前的时间加上雪花算法进行实现
        String orderNo = DateUtil.today().replace("-", "") + IdUtil.getSnowflakeNextIdStr();
        orderInfo.setOrderNo(orderNo);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        //3.封装订单明细列表
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        OrderDetail orderDetail1 = BeanUtil.copyProperties(orderDetailVoList, OrderDetail.class);
        orderInfo.setOrderDetailList(Arrays.asList(orderDetail1));

        if (CollUtil.isNotEmpty(orderDetailVoList)) {
            String itemName = orderDetailVoList.get(0).getItemName();
            orderInfo.setOrderTitle(itemName);
        }
        orderInfoMapper.insert(orderInfo);

        //4.保存订单明细
        Long id = orderInfo.getId();
        if (CollUtil.isNotEmpty(orderDetailVoList)) {
            orderDetailVoList.stream().forEach(orderDetailVo -> {
                OrderDetail orderDetail = BeanUtil.copyProperties(orderDetailVo, OrderDetail.class);
                orderDetail.setOrderId(id);
                orderDetailMapper.insert(orderDetail);
            });


            //5.保存订单减免明细
            List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
            if (CollUtil.isNotEmpty(orderDerateVoList)) {
                orderDerateVoList.stream().forEach(orderDearteVoList -> {
                    OrderDerate orderDerate = BeanUtil.copyProperties(orderDearteVoList, OrderDerate.class);
                    orderDerate.setOrderId(orderInfo.getId());
                    orderDerateMapper.insert(orderDerate);
                });
            }
        }
        return orderInfo;
    }

    @Override
    public OrderInfo getOrderInfo(String orderNo) {
        //1.查询订单表
        OrderInfo orderInfo = orderInfoMapper.selectOne(
                new LambdaQueryWrapper<OrderInfo>()
                        .eq(OrderInfo::getOrderNo, orderNo)
        );
        if (orderInfo == null) {
            throw new GuiguException(500, "订单不存在！");
        }
        //2.查询订单明细表
        Long orderId = orderInfo.getId();

        List<OrderDetail> orderDetail = orderDetailMapper.selectList(
                new LambdaQueryWrapper<OrderDetail>()
                        .eq(OrderDetail::getOrderId, orderId)
        );
        if (CollUtil.isNotEmpty(orderDetail)) {
            orderInfo.setOrderDetailList(orderDetail);
        }
        //3.查询订单减免表
        List<OrderDerate> orderDerates = orderDerateMapper.selectList(
                new LambdaQueryWrapper<OrderDerate>()
                        .eq(OrderDerate::getOrderId, orderId)
        );
        if (CollUtil.isNotEmpty(orderDerates)) {
            orderInfo.setOrderDerateList(orderDerates);
        }
        return orderInfo;
    }

    @Override
    public Page<OrderInfo> findUserPage(Page<OrderInfo> orderInfoPage, Long userId) {
        //1 分页查询订单表 得到page对象, 遍历page 将查到的订单详情封装到orderInfo对象中
        //2 写一个动态的sql 查询订单表和订单详情表
        //3 分页查询订单表得到订单的id , 查询详情表 ,遍历详情表,将id 封装到详情对象中
        Page<OrderInfo> page = orderInfoMapper.selectPage(orderInfoPage,
                new LambdaQueryWrapper<OrderInfo>()
                        .eq(OrderInfo::getUserId, userId)
                        .orderByDesc(OrderInfo::getCreateTime)
        );
        List<OrderInfo> collect =
                page.getRecords().stream().collect(Collectors.toList());

        List<OrderDetail> orderDetails = orderDetailMapper.selectList(
                new LambdaQueryWrapper<OrderDetail>()
                        .in(OrderDetail::getOrderId, collect)
        );

        Map<Long, List<OrderDetail>> map =
                orderDetails.stream().collect(Collectors.groupingBy(OrderDetail::getOrderId));
        page.getRecords().stream().forEach(orderInfo ->
        {
            orderInfo.setOrderDetailList(map.get(orderInfo.getId()));
        });
        return page;
    }

    @Override
    public void cancel(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        String orderStatus = orderInfo.getOrderStatus();
        if (SystemConstant.ORDER_STATUS_UNPAID.equals(orderStatus)) {
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
            orderInfoMapper.updateById(orderInfo);
        }
    }

    @Override
    public void orderPaySuccess(String orderNo) {

        OrderInfo orderInfo = this.getOrderInfo(orderNo);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);

        orderInfoMapper.updateById(orderInfo);

        //1.保存用户支付记录并且发货
        UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
        userPaidRecordVo.setOrderNo(orderNo);
        userPaidRecordVo.setUserId(orderInfo.getUserId());
        userPaidRecordVo.setItemType(orderInfo.getItemType());

        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        if (CollUtil.isNotEmpty(orderDetailList)) {
            List<Long> longs = orderDetailList.stream().map(OrderDetail::getItemId).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(longs);
        }

        //2.调用发货虚拟商品接口
        Result result = userFeignClient.savePaidRecord(userPaidRecordVo);
        if (result.getCode().intValue() != 200) {
            throw new GuiguException(result.getCode(), result.getMessage());
        }
    }
}
